package com.yilijk.base.network.https.interceptor.httplog;



import static com.yilijk.base.network.bean.AttestationBean.ERROR_METHOD_NOT_ALLOWED;

import android.os.SystemClock;
import android.text.TextUtils;

import androidx.annotation.NonNull;

import com.google.gson.Gson;
import com.yilijk.base.AppBase;
import com.yilijk.base.network.bean.AttestationBean;
import com.yilijk.base.network.config.BaseConfig;
import com.yilijk.base.network.https.NetAttestationUtils;
import com.yilijk.base.utils.ALog;
import com.yilijk.base.utils.DevicesUtils;
import com.yilijk.base.utils.MD5Utils;
import com.yilijk.base.utils.OpenUtils;
import com.yilijk.base.utils.RSAUtils;

import org.json.JSONObject;

import java.io.IOException;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;

/**
 * Created by SHICHENG
 * on 2021/10/22.
 */
public class HttpLogInterceptor implements Interceptor {

    private static HashMap<String, String> headerIgnoreMap = new HashMap<>();
    private static final String CONSTANT_SALT = "salt";
    private static final String CONSTANT_TIMESTAMP = "timestamp";
    private static final String CONSTANT_REQUEST_BODY = "requestBody";
    private static final int SALT_RETRY_TIMES = 5;

    static {
        headerIgnoreMap.put("Host", "");
        headerIgnoreMap.put("Connection", "");
        headerIgnoreMap.put("Accept-Encoding", "");
    }

    protected void log(String message) {
        ALog.i("网络请求", message);
    }

    private boolean isPlainText(MediaType mediaType) {
        if (null != mediaType) {
            String mediaTypeString = (null != mediaType ? mediaType.toString() : null);
            if (!TextUtils.isEmpty(mediaTypeString)) {
                mediaTypeString = mediaTypeString.toLowerCase();
                if (mediaTypeString.contains("text") || mediaTypeString.contains("application/json")) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public synchronized Response intercept(Chain chain) throws IOException {
        String url = chain.request().url().toString();

//        String uuid = DevicesUtils.getDeviceNo();
        String uuid = DevicesUtils.DEVICES_UUID;
        String timestamp = System.currentTimeMillis() + "";
        String sign = "";
        boolean isGetSalt = url.contains(BaseConfig.Constants.zuulGetSalt);
        if (!TextUtils.isEmpty(uuid)) {
            if (OpenUtils.getInstance().isOpenAttestation()) {
                if (isGetSalt) {
                    try {
                        uuid = RSAUtils.encryptPublicSaltKey(uuid);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else {
                    String salt = NetAttestationUtils.getInstance().getSALT();
                    if (TextUtils.isEmpty(salt)) {
                        salt = NetAttestationUtils.getInstance().getSaltExecute(AppBase.getApplication());
                    }
                    sign = MD5Utils.md5(getRequestSign(chain.request(), salt, timestamp));
                }
            }
        }
        ALog.e("oakkk", "uuid: " + uuid);

        Request request = getBuild(chain, uuid, timestamp, sign);
        long startTime = SystemClock.elapsedRealtime();
        Response response = chain.proceed(request);

//        while (isSignInvalid(response) && !isGetSalt) {
        int times = 0;
        while (isSignInvalid(response) && times < SALT_RETRY_TIMES) {
            times++;
            NetAttestationUtils.getInstance().setSALT("");
            NetAttestationUtils.getInstance().getSaltExecute(AppBase.getApplication());

//            String newUuid = DevicesUtils.getDeviceNo();
            String newUuid = DevicesUtils.DEVICES_UUID;
            String newTimestamp = System.currentTimeMillis() + "";
            String newSign = "";
            if (isGetSalt) {
                try {
                    newUuid = RSAUtils.encryptPublicSaltKey(newUuid);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                String salt = NetAttestationUtils.getInstance().getSALT();
                newSign = MD5Utils.md5(getRequestSign(chain.request(), salt, newTimestamp));
            }

            Request newRequest = getBuild(chain, newUuid, newTimestamp, newSign);
            response = chain.proceed(newRequest);
        }

        long endTime = SystemClock.elapsedRealtime();
        long duration = endTime - startTime;

        JSONObject jsonObjectHead = new JSONObject();
        //url
//        String url = request.url().toString();

        log("┌───────Request Start────────────────────────────");
        log("请求方式 -->>" + request.method() + ": " + url);
        log("请求方式 -->>" + "Time:" + duration + " ms");
        //headers
        Headers headers = request.headers();
        if (null != headers) {
            log("请求头部 -->>  [─────────────Request Header Message────────────]");
            for (int i = 0, count = headers.size(); i < count; i++) {
                if (!headerIgnoreMap.containsKey(headers.name(i))) {
                    log("       -->>" + headers.name(i) + ": " + headers.value(i));
                }
            }
            log("请求头部 -->>  [───────────────────────────────────────────────]");
        }
        //param
        RequestBody requestBody = request.body();
        String paramString = readRequestParamString(requestBody);

        if (!TextUtils.isEmpty(paramString)) {
            log("请求参数 -->>" + paramString);
        }

        //response
        ResponseBody responseBody = response.body();
        String responseString = "";
        if (null != responseBody) {
            if (isPlainText(responseBody.contentType())) {
                responseString = readContent(response);
            } else {
                responseString = "other-type=" + responseBody.contentType();
            }
        }
        log("请求返回 -->>" + responseString);

        log("└───────Request End─────────────────────────────" + "\n" + "-");
        return response;
    }

    private boolean isSignInvalid(Response response) {
        if (response != null && response.body() != null && !TextUtils.isEmpty(readContent(response))) {
            ALog.e("oakkk", "response body: " + readContent(response));
            AttestationBean bean = null;
            try {
                bean = new Gson().fromJson(readContent(response), AttestationBean.class);
            } catch (Throwable ignored) {

            }
            return bean != null && bean.getData() != null && ERROR_METHOD_NOT_ALLOWED.equals(bean.getData().getCode());
        }
        return false;
    }

    @NonNull
    private Request getBuild(Chain chain, String uuid, String timestamp, String sign) {
        String s = chain.request().url().toString();
        if (OpenUtils.getInstance().isOpenAttestation()) {
            return chain.request().newBuilder()
                    .addHeader("SV", DevicesUtils.getSaltVersion())
                    .addHeader("token", DevicesUtils.getToken())
                    .addHeader("uuid", uuid)
                    .addHeader("sign", sign)
                    .addHeader(CONSTANT_TIMESTAMP, timestamp)
                    .addHeader("YLS", DevicesUtils.getTerminal())
//                    .addHeader("IV", DevicesUtils.getVersionName())
                    .addHeader("IV", "2.3.3")
                    .addHeader("deviceManuFacturer", DevicesUtils.getDeviceManuFacturer())
                    .addHeader("terminal", DevicesUtils.getTerminal())
                    .addHeader("deviceNo", DevicesUtils.getDeviceNo())
                    .addHeader("IPAddress", DevicesUtils.getIPAddress())
                    .addHeader("isEnvironment", String.valueOf(DevicesUtils.isEnvironment()))
                    .addHeader("version", DevicesUtils.getVersionName())
                    .addHeader("deviceId", DevicesUtils.getDeviceId())
                    .addHeader("deviceName", DevicesUtils.getDeviceName())
                    .addHeader("SDKVersion", DevicesUtils.getSDKVersion())
                    .addHeader("currentVersion", String.valueOf(DevicesUtils.getVersionCode()))
                    .addHeader("deviceBrand", DevicesUtils.getDeviceBrand())
                    .addHeader("apkType", OpenUtils.getInstance().getApkType())
                    .build();
        } else {
            return chain.request().newBuilder()
                    .addHeader("token", DevicesUtils.getToken())
                    .addHeader(CONSTANT_TIMESTAMP, timestamp)
                    .addHeader("YLS", DevicesUtils.getTerminal())
//                    .addHeader("IV", DevicesUtils.getVersionName())
                    .addHeader("IV", "2.3.3")
                    .addHeader("deviceManuFacturer", DevicesUtils.getDeviceManuFacturer())
                    .addHeader("terminal", DevicesUtils.getTerminal())
                    .addHeader("deviceNo", DevicesUtils.getDeviceNo())
                    .addHeader("IPAddress", DevicesUtils.getIPAddress())
                    .addHeader("isEnvironment", String.valueOf(DevicesUtils.isEnvironment()))
                    .addHeader("version", DevicesUtils.getVersionName())
                    .addHeader("deviceId", DevicesUtils.getDeviceId())
                    .addHeader("deviceName", DevicesUtils.getDeviceName())
                    .addHeader("SDKVersion", DevicesUtils.getSDKVersion())
                    .addHeader("currentVersion", String.valueOf(DevicesUtils.getVersionCode()))
                    .addHeader("deviceBrand", DevicesUtils.getDeviceBrand())
                    .addHeader("apkType", OpenUtils.getInstance().getApkType())
                    .build();
        }
    }

    private String getRequestSign(Request request, String salt, String timestamp) {
        try {
            String method = request.method();
            ALog.e("getRequestSign", "method: " + method);
            ALog.e("getRequestSign", "url: " + request.url().toString());
            if ("GET".equals(method) || "DELETE".equals(method)) {
                //获取到请求地址api
                HttpUrl httpUrl = request.url();
                Set<String> queryNames = httpUrl.queryParameterNames();
                ALog.e("getRequestSign", "query: " + httpUrl.query());
                ALog.e("getRequestSign", "query names: " + new Gson().toJson(queryNames));
                Set<String> treeSet = new TreeSet<>(new Comparator<String>() {
                    @Override
                    public int compare(String o1, String o2) {
                        return o1.compareTo(o2);
                    }
                });
                treeSet.addAll(queryNames);
                treeSet.add(CONSTANT_SALT);
                treeSet.add(CONSTANT_TIMESTAMP);
                ALog.e("getRequestSign", "query names: " + treeSet);
                StringBuffer stringBuffer = new StringBuffer("");
                for (String query : treeSet) {
                    if (CONSTANT_SALT.equals(query)) {
                        stringBuffer.append(CONSTANT_SALT).append(salt);
                    } else if (CONSTANT_TIMESTAMP.equals(query)) {
                        stringBuffer.append(CONSTANT_TIMESTAMP).append(timestamp);
                    } else {
                        String value = httpUrl.queryParameter(query);
                        stringBuffer.append(query).append(value);
                    }
                }
                ALog.e("getRequestSign", "query get names: " + stringBuffer);
                return stringBuffer.toString();
            } else if ("POST".equals(method) || "PUT".equals(method)) {
                TreeMap<String, String> treeMap = new TreeMap<>(new Comparator<String>() {
                    @Override
                    public int compare(String o1, String o2) {
                        return o1.compareTo(o2);
                    }
                });
                treeMap.put(CONSTANT_SALT, salt);
                treeMap.put(CONSTANT_TIMESTAMP, timestamp);
                String  requestBodyStr = readRequestParamString(request.body());
                if (!TextUtils.isEmpty(requestBodyStr)) {
                    treeMap.put(CONSTANT_REQUEST_BODY, requestBodyStr);
                }
                StringBuffer buffer = new StringBuffer("");
                for (String key : treeMap.keySet()) {
                    buffer.append(key).append(treeMap.get(key));
                }

                ALog.e("getRequestSign", "query post names: " + buffer.toString());
                return buffer.toString();
            }
        } catch (Throwable ignored) {

        }
        return "null";
    }

    private String readRequestParamString(RequestBody requestBody) {
        String paramString;
        if (requestBody instanceof MultipartBody) {//判断是否有文件
            StringBuilder sb = new StringBuilder();
            MultipartBody body = (MultipartBody) requestBody;
            List<MultipartBody.Part> parts = body.parts();
            RequestBody partBody;
            for (int i = 0, size = parts.size(); i < size; i++) {
                partBody = parts.get(i).body();
                if (null != partBody) {
                    if (sb.length() > 0) {
                        sb.append(",");
                    }
                    if (isPlainText(partBody.contentType())) {
                        sb.append(readContent(partBody));
                    } else {
                        sb.append("other-param-type=").append(partBody.contentType());
                    }
                }
            }
            paramString = sb.toString();
        } else {
            paramString = readContent(requestBody);
        }
        return paramString;
    }

    private String readContent(Response response) {
        if (response == null) {
            return "";
        }

        try {
            return response.peekBody(Long.MAX_VALUE).string();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    private String readContent(RequestBody body) {
        if (body == null) {
            return "";
        }

        Buffer buffer = new Buffer();

        try {
            //小于2m
            if (body.contentLength() <= 2 * 1024 * 1024) {
                body.writeTo(buffer);
            } else {
                return "content is more than 2M";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return buffer.readUtf8();
    }

    private boolean isEndWith(String s){
        String[] strings = OpenUtils.getInstance().rnUpdataUrl();
        for (int i = 0; i < strings.length; i++) {
            if (s.endsWith(strings[i])){
                return true;
            }
        }
        return false;
    }

}
